#pragma once

#include <functional>
#include <memory>
#include <string>
#include <sys/epoll.h>

constexpr int KInitEventListSize = 32;
constexpr int KNew = -1;
constexpr int KAdded = 1;
constexpr int KDeleted = 2;

constexpr int KNoneEvent = 0;
constexpr int KReadEvent = EPOLLIN | EPOLLPRI;
constexpr int KWriteEvent = EPOLLOUT;

class EventLoop;

class Channel
{
public:
    Channel(EventLoop *loop, int fd);

    ~Channel();

    void setReadCallback(std::function<int> cb);
    void setWriteCallback(std::function<int> cb);
    void setCloseCallback(std::function<int> cb);
    void setErrorCallback(std::function<int> cb);

    std::string name() { return name_; }

    void tie(const std::shared_ptr<void> &ptr);

    int fd() { return fd_; }

    int event() { return event_; }

    int revent() { return revent_; }

    void enableRead()
    {
        event_ |= EPOLLIN | EPOLLPRI;
        update();
    }
    void disableRead()
    {
        event_ &= ~(EPOLLIN | EPOLLPRI);
        update();
    }
    void enableWrite()
    {
        event_ |= EPOLLOUT;
        update();
    }
    void disableWrite()
    {
        event_ &= ~EPOLLOUT;
        update();
    }
    void disableAll()
    {
        event_ = KNoneEvent;
        update();
    }

    void handleEvent();

    void setRevent(int revent) { revent_ = revent; }

    std::string getReventMsg();

    std::string getEventMsg();

    void setReadCallback(std::function<void()> cb) { this->readCallback_ = cb; }
    void setWriteCallback(std::function<void()> cb) { this->writeCallback_ = cb; }
    void setCloseCallback(std::function<void()> cb) { this->closeCallback_ = cb; }
    void setErrorCallback(std::function<void()> cb) { this->errorCallback_ = cb; }

    void setIndex(int idx) { index_ = idx; }

    int index() { return index_; }

    EventLoop *ownerLoop() { return loop_; }

    bool isNoneEvent() { return event_ == KNoneEvent; }

    bool isReading() { return event_ & KReadEvent; }

    bool isWriting() { return event_ & KWriteEvent; }

    void remove();

private:
    void update();

    void handleRead();

    void handleWrite();

    void handleError();

    void handleClose();

    void eventHandleWithGuard();

private:
    std::weak_ptr<void> tie_;
    bool tied_;
    EventLoop *loop_;
    int fd_;
    std::string name_;
    int index_; // for epoller
    int event_;
    int revent_;
    bool addedToLoop_;
    bool eventHandling_;
    std::function<void()> readCallback_;
    std::function<void()> writeCallback_;
    std::function<void()> closeCallback_;
    std::function<void()> errorCallback_;
};